#include "modelitembrushdelegate.h"
#include "modelitembrusheditor.h"

#include <QEvent>
#include <QPainter>
#include <QPainterPath>

ModelItemBrushDelegate::ModelItemBrushDelegate(const QPainterPath &path, QObject *parent):
    QStyledItemDelegate(parent),
    m_path(path)
{
}

void ModelItemBrushDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (index.data().canConvert<QBrush>())
    {
        QStyledItemDelegate::paint(painter, option, index);

        if ((option.state & QStyle::State_Enabled) == 0)
            return;

        QBrush brush = qvariant_cast<QBrush>(index.data());

        painter->save();

        QRect r = option.rect.adjusted(2, 2, -2, -2);
        painter->setClipRect(r);

        // Draw the chess pattern for transparency
        const int cellSize = 8;
        QRect cell(0, 0, cellSize, cellSize);
        cell.translate(r.topLeft());
        for (int col = 0; col < (r.width()/cellSize+1); col++)
        {
            for (int row = 0; row < (r.height()/cellSize+1); row++)
            {
                if ((row%2 == 0 && col%2 == 0) || (row%2 == 1 && col%2 == 1))
                    painter->fillRect(cell.translated(col*cellSize, row*cellSize), QColor("#ffffff"));
                else
                    painter->fillRect(cell.translated(col*cellSize, row*cellSize), QColor("#dddddd"));
            }
        }

        painter->translate(r.center());
        painter->setBrush(brush);
        painter->setPen(Qt::NoPen);
        painter->drawPath(m_path);

        painter->restore();
    }
    else
    {
        QStyledItemDelegate::paint(painter, option, index);
    }
}

QSize ModelItemBrushDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (index.data().canConvert<QBrush>())
    {
        return QSize(32, 32);
    }
    else
    {
        return QStyledItemDelegate::sizeHint(option, index);
    }
}

QWidget *ModelItemBrushDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (index.data().canConvert<QBrush>())
    {
        auto editor = new ModelItemBrushEditor(parent);
        editor->setFocusPolicy(Qt::StrongFocus);
        editor->setPath(m_path);
        connect(editor, &ModelItemBrushEditor::accepted,
                this, &ModelItemBrushDelegate::editorAccepted);
        connect(editor, &ModelItemBrushEditor::rejected,
                this, &ModelItemBrushDelegate::editorRejected);
        return editor;
    }
    else
    {
        return QStyledItemDelegate::createEditor(parent, option, index);
    }
}

void ModelItemBrushDelegate::destroyEditor(QWidget *editor, const QModelIndex &index) const
{
    if (index.data().canConvert<QBrush>())
    {
        editor->parentWidget()->update();
    }
    QStyledItemDelegate::destroyEditor(editor, index);
}

void ModelItemBrushDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if (index.data().canConvert<QBrush>())
    {
        auto brush = qvariant_cast<QBrush>(index.data());
        auto brushEditor = qobject_cast<ModelItemBrushEditor *>(editor);
        brushEditor->setBrush(brush);
    }
    else
    {
        QStyledItemDelegate::setEditorData(editor, index);
    }
}

void ModelItemBrushDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    if (index.data().canConvert<QBrush>())
    {
        auto *brushEditor = qobject_cast<ModelItemBrushEditor *>(editor);
        model->setData(index, QVariant::fromValue(brushEditor->brush()));
    }
    else
    {
        QStyledItemDelegate::setModelData(editor, model, index);
    }
}

void ModelItemBrushDelegate::editorAccepted()
{
    auto editor = qobject_cast<ModelItemBrushEditor*>(sender());
    emit commitData(editor);
    // No hint to avoid auto commit on the model
    emit closeEditor(editor, QAbstractItemDelegate::NoHint);
}

void ModelItemBrushDelegate::editorRejected()
{
    auto editor = qobject_cast<ModelItemBrushEditor*>(sender());
    emit closeEditor(editor, QAbstractItemDelegate::NoHint);
}
